import sys
import os
import subprocess
import concurrent.futures
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, 
    QPushButton, QFileDialog, QTableWidget, QTableWidgetItem, QHeaderView,
    QTabWidget, QTextEdit, QProgressBar, QMessageBox, QFileIconProvider,
    QSplitter, QMenu, QAction, QToolBar, QStatusBar, QStyle
)
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QSize
from PyQt5.QtGui import QFont, QIcon, QColor, QPalette

class ConversionWorker(QThread):
    """转换工作线程"""
    progress_updated = pyqtSignal(int)
    file_completed = pyqtSignal(str, str)  # 文件路径, 状态
    log_message = pyqtSignal(str)
    conversion_finished = pyqtSignal()
    conversion_started = pyqtSignal()
    
    def __init__(self, file_paths, max_workers=4):
        super().__init__()
        self.file_paths = file_paths
        self.max_workers = max_workers
        self.running = True
    
    def run(self):
        self.conversion_started.emit()
        completed_files = 0
        total_files = len(self.file_paths)
        
        with concurrent.futures.ThreadPoolExecutor(max_workers=self.max_workers) as executor:
            # 提交所有转换任务
            future_to_file = {
                executor.submit(self.convert_file, file_path): file_path 
                for file_path in self.file_paths
            }
            
            # 处理完成的任务
            for future in concurrent.futures.as_completed(future_to_file):
                if not self.running:
                    break
                    
                file_path = future_to_file[future]
                try:
                    status = future.result()
                except Exception as e:
                    status = "错误"
                    self.log_message.emit(f"✗ 处理文件时出错: {file_path}")
                    self.log_message.emit(f"错误详情: {str(e)}")
                
                self.file_completed.emit(file_path, status)
                completed_files += 1
                progress = int((completed_files / total_files) * 100)
                self.progress_updated.emit(progress)
        
        if self.running:
            self.conversion_finished.emit()
    
    def convert_file(self, file_path):
        """转换单个文件"""
        try:
            # 获取文件所在目录和文件名
            file_dir = os.path.dirname(file_path)
            file_name = os.path.basename(file_path)
            
            self.log_message.emit(f"开始转换: {file_name}")
            
            # 构造命令
            cmd = ["jupyter", "nbconvert", "--to", "markdown", file_name]
            
            # 在文件所在目录执行命令
            process = subprocess.run(
                cmd, 
                cwd=file_dir,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                text=True
            )
            
            # 返回状态
            if process.returncode == 0:
                self.log_message.emit(f"✓ 成功转换: {file_name}")
                return "转换成功"
            else:
                self.log_message.emit(f"✗ 转换失败: {file_name}")
                self.log_message.emit(f"错误信息: {process.stderr}")
                return "转换失败"
        except Exception as e:
            raise e
    
    def stop(self):
        """停止转换"""
        self.running = False
        self.wait()

class NB2MDConverter(QMainWindow):
    """Jupyter Notebook 转 Markdown 主窗口"""
    
    def __init__(self):
        super().__init__()
        self.file_paths = []
        self.conversion_worker = None
        self.init_ui()
        self.apply_style()
    
    def init_ui(self):
        """初始化用户界面"""
        # 设置窗口标题和大小
        self.setWindowTitle("Jupyter Notebook 转 Markdown 工具")
        self.resize(900, 600)
        
        # 创建中央部件
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        
        # 主布局
        main_layout = QVBoxLayout(central_widget)
        main_layout.setContentsMargins(10, 10, 10, 10)
        
        # 创建工具栏
        self.create_toolbar()
        
        # 创建分割器
        splitter = QSplitter(Qt.Vertical)
        
        # 创建文件表格
        self.create_file_table(splitter)
        
        # 创建标签页部件
        self.tab_widget = QTabWidget()
        
        # 创建日志标签页
        self.log_text = QTextEdit()
        self.log_text.setReadOnly(True)
        self.log_text.setLineWrapMode(QTextEdit.WidgetWidth)
        self.log_text.setUndoRedoEnabled(False)
        self.tab_widget.addTab(self.log_text, "转换日志")
        
        # 添加标签页到分割器
        splitter.addWidget(self.tab_widget)
        
        # 设置分割器比例
        splitter.setSizes([400, 200])
        
        # 添加分割器到主布局
        main_layout.addWidget(splitter, 1)
        
        # 创建进度条
        self.progress_bar = QProgressBar()
        self.progress_bar.setValue(0)
        self.progress_bar.setFormat("准备就绪")
        main_layout.addWidget(self.progress_bar)
        
        # 创建状态栏
        self.statusBar = QStatusBar()
        self.setStatusBar(self.statusBar)
        self.statusBar.showMessage("准备就绪")
        
        # 连接信号槽
        self.connect_signals_slots()
    
    def create_toolbar(self):
        """创建工具栏"""
        toolbar = QToolBar("主工具栏")
        toolbar.setIconSize(QSize(16, 16))
        self.addToolBar(toolbar)
        
        # 添加文件按钮
        add_files_action = QAction(
            self.style().standardIcon(QStyle.SP_DialogOpenButton), 
            "添加文件", 
            self
        )
        add_files_action.triggered.connect(self.add_files)
        toolbar.addAction(add_files_action)
        
        # 添加文件夹按钮
        add_folder_action = QAction(
            self.style().standardIcon(QStyle.SP_DirOpenIcon), 
            "添加文件夹", 
            self
        )
        add_folder_action.triggered.connect(self.add_folder)
        toolbar.addAction(add_folder_action)
        
        toolbar.addSeparator()
        
        # 移除文件按钮
        remove_file_action = QAction(
            self.style().standardIcon(QStyle.SP_TrashIcon), 
            "移除选中文件", 
            self
        )
        remove_file_action.triggered.connect(self.remove_selected)
        toolbar.addAction(remove_file_action)
        
        # 清空列表按钮
        clear_list_action = QAction(
            self.style().standardIcon(QStyle.SP_BrowserStop), 
            "清空列表", 
            self
        )
        clear_list_action.triggered.connect(self.clear_list)
        toolbar.addAction(clear_list_action)
        
        toolbar.addSeparator()
        
        # 开始转换按钮
        self.convert_action = QAction(
            self.style().standardIcon(QStyle.SP_MediaPlay), 
            "开始转换", 
            self
        )
        self.convert_action.triggered.connect(self.start_conversion)
        toolbar.addAction(self.convert_action)
        
        # 停止转换按钮
        self.stop_action = QAction(
            self.style().standardIcon(QStyle.SP_MediaStop), 
            "停止转换", 
            self
        )
        self.stop_action.triggered.connect(self.stop_conversion)
        self.stop_action.setEnabled(False)
        toolbar.addAction(self.stop_action)
    
    def create_file_table(self, parent):
        """创建文件表格"""
        self.file_table = QTableWidget(0, 3)
        self.file_table.setHorizontalHeaderLabels(["", "文件路径", "状态"])
        self.file_table.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeToContents)
        self.file_table.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
        self.file_table.horizontalHeader().setSectionResizeMode(2, QHeaderView.ResizeToContents)
        self.file_table.setSelectionBehavior(QTableWidget.SelectRows)
        self.file_table.setContextMenuPolicy(Qt.CustomContextMenu)
        
        # 设置图标提供器
        self.icon_provider = QFileIconProvider()
        
        parent.addWidget(self.file_table)
    
    def connect_signals_slots(self):
        """连接信号和槽"""
        # 表格右键菜单
        self.file_table.customContextMenuRequested.connect(self.show_table_context_menu)
        
        # 表格选择变化
        self.file_table.itemSelectionChanged.connect(self.update_button_states)
    
    def apply_style(self):
        """应用样式"""
        # 设置字体
        font = QFont("Microsoft YaHei UI", 9)
        self.setFont(font)
        
        # 获取当前样式表
        app = QApplication.instance()
        if "windows" in app.style().objectName().lower():
            # 为Windows系统应用现代样式
            self.setStyleSheet("""
                QMainWindow, QWidget {
                    background-color: #f5f5f5;
                }
                QTableWidget {
                    background-color: white;
                    border: 1px solid #ddd;
                    border-radius: 4px;
                    alternate-background-color: #f9f9f9;
                }
                QHeaderView::section {
                    background-color: #eaeaea;
                    padding: 6px;
                    border: 1px solid #ddd;
                }
                QTableWidget::item {
                    padding: 5px;
                }
                QToolBar {
                    background-color: #f0f0f0;
                    border: none;
                }
                QProgressBar {
                    border-radius: 4px;
                    text-align: center;
                    height: 20px;
                }
                QProgressBar::chunk {
                    background-color: #4CAF50;
                    border-radius: 4px;
                }
                QPushButton {
                    padding: 5px 10px;
                    border-radius: 3px;
                }
                QPushButton:hover {
                    background-color: #e0e0e0;
                }
                QTabWidget::pane {
                    background-color: white;
                    border: 1px solid #ddd;
                    border-top: none;
                }
                QTabBar::tab {
                    padding: 6px 12px;
                    background-color: #f0f0f0;
                    border: 1px solid #ddd;
                    margin-right: 2px;
                }
                QTabBar::tab:selected {
                    background-color: white;
                    border-bottom-color: white;
                }
            """)
    
    def log(self, message):
        """添加日志消息"""
        self.log_text.append(message)
        self.log_text.verticalScrollBar().setValue(
            self.log_text.verticalScrollBar().maximum()
        )
    
    def add_files(self):
        """添加文件"""
        files, _ = QFileDialog.getOpenFileNames(
            self,
            "选择Jupyter Notebook文件",
            "",
            "Jupyter Notebook (*.ipynb)"
        )
        
        if files:
            added_count = 0
            for file_path in files:
                if file_path not in self.file_paths:
                    self.file_paths.append(file_path)
                    row_position = self.file_table.rowCount()
                    self.file_table.insertRow(row_position)
                    
                    # 添加图标
                    icon = self.icon_provider.icon(QFileIconProvider.File)
                    icon_item = QTableWidgetItem()
                    icon_item.setIcon(icon)
                    self.file_table.setItem(row_position, 0, icon_item)
                    
                    # 添加文件路径
                    path_item = QTableWidgetItem(file_path)
                    path_item.setToolTip(file_path)
                    self.file_table.setItem(row_position, 1, path_item)
                    
                    # 添加状态
                    status_item = QTableWidgetItem("待转换")
                    status_item.setTextAlignment(Qt.AlignCenter)
                    self.file_table.setItem(row_position, 2, status_item)
                    
                    added_count += 1
            
            self.log(f"已添加 {added_count} 个文件")
            self.statusBar.showMessage(f"已添加 {added_count} 个文件")
            self.update_button_states()
    
    def add_folder(self):
        """添加文件夹中的所有ipynb文件"""
        folder = QFileDialog.getExistingDirectory(
            self,
            "选择包含Jupyter Notebook文件的文件夹"
        )
        
        if folder:
            added_count = 0
            for root_dir, _, files in os.walk(folder):
                for file in files:
                    if file.lower().endswith('.ipynb'):
                        file_path = os.path.join(root_dir, file)
                        if file_path not in self.file_paths:
                            self.file_paths.append(file_path)
                            row_position = self.file_table.rowCount()
                            self.file_table.insertRow(row_position)
                            
                            # 添加图标
                            icon = self.icon_provider.icon(QFileIconProvider.File)
                            icon_item = QTableWidgetItem()
                            icon_item.setIcon(icon)
                            self.file_table.setItem(row_position, 0, icon_item)
                            
                            # 添加文件路径
                            path_item = QTableWidgetItem(file_path)
                            path_item.setToolTip(file_path)
                            self.file_table.setItem(row_position, 1, path_item)
                            
                            # 添加状态
                            status_item = QTableWidgetItem("待转换")
                            status_item.setTextAlignment(Qt.AlignCenter)
                            self.file_table.setItem(row_position, 2, status_item)
                            
                            added_count += 1
            
            if added_count > 0:
                self.log(f"从文件夹 {folder} 中添加了 {added_count} 个.ipynb文件")
                self.statusBar.showMessage(f"从文件夹添加了 {added_count} 个文件")
            else:
                self.log(f"文件夹 {folder} 中没有找到.ipynb文件")
                self.statusBar.showMessage("未找到.ipynb文件")
            
            self.update_button_states()
    
    def remove_selected(self):
        """移除选中的文件"""
        selected_rows = set()
        for item in self.file_table.selectedItems():
            selected_rows.add(item.row())
        
        if not selected_rows:
            QMessageBox.information(self, "提示", "请先选择要移除的文件")
            return
        
        # 按行号降序排序，从下往上删除
        for row in sorted(selected_rows, reverse=True):
            file_path = self.file_table.item(row, 1).text()
            self.file_paths.remove(file_path)
            self.file_table.removeRow(row)
        
        self.log(f"已移除 {len(selected_rows)} 个文件")
        self.statusBar.showMessage(f"已移除 {len(selected_rows)} 个文件")
        self.update_button_states()
    
    def clear_list(self):
        """清空文件列表"""
        if not self.file_paths:
            return
        
        if QMessageBox.question(
            self, 
            "确认", 
            "确定要清空所有文件吗？",
            QMessageBox.Yes | QMessageBox.No
        ) == QMessageBox.Yes:
            self.file_table.setRowCount(0)
            self.file_paths.clear()
            self.log("已清空所有文件")
            self.statusBar.showMessage("已清空所有文件")
            self.update_button_states()
    
    def update_button_states(self):
        """更新按钮状态"""
        has_files = len(self.file_paths) > 0
        has_selection = len(self.file_table.selectedItems()) > 0
        
        # 更新移除按钮状态
        for action in self.findChildren(QAction):
            if action.text() == "移除选中文件":
                action.setEnabled(has_selection)
            elif action.text() == "清空列表":
                action.setEnabled(has_files)
            elif action.text() == "开始转换":
                action.setEnabled(has_files and self.conversion_worker is None)
    
    def show_table_context_menu(self, position):
        """显示表格右键菜单"""
        menu = QMenu()
        
        # 添加移除选中项动作
        remove_action = QAction("移除选中项", self)
        remove_action.triggered.connect(self.remove_selected)
        remove_action.setEnabled(len(self.file_table.selectedItems()) > 0)
        menu.addAction(remove_action)
        
        # 添加清空列表动作
        clear_action = QAction("清空列表", self)
        clear_action.triggered.connect(self.clear_list)
        clear_action.setEnabled(len(self.file_paths) > 0)
        menu.addAction(clear_action)
        
        menu.exec_(self.file_table.mapToGlobal(position))
    
    def start_conversion(self):
        """开始转换所有文件"""
        # 检查是否已安装jupyter
        try:
            subprocess.run(["jupyter", "--version"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
        except FileNotFoundError:
            QMessageBox.critical(self, "错误", "未找到jupyter命令，请确保已安装Jupyter Notebook")
            return
        
        # 禁用相关按钮
        self.convert_action.setEnabled(False)
        self.stop_action.setEnabled(True)
        
        # 重置进度条
        self.progress_bar.setValue(0)
        self.progress_bar.setFormat("正在转换... %p%")
        
        self.log("===== 开始批量转换 =====")
        self.statusBar.showMessage("正在转换文件...")
        
        # 创建并启动转换工作线程
        self.conversion_worker = ConversionWorker(self.file_paths.copy())
        
        # 连接信号槽
        self.conversion_worker.progress_updated.connect(self.progress_bar.setValue)
        self.conversion_worker.file_completed.connect(self.update_file_status)
        self.conversion_worker.log_message.connect(self.log)
        self.conversion_worker.conversion_finished.connect(self.conversion_completed)
        
        # 启动线程
        self.conversion_worker.start()
    
    def stop_conversion(self):
        """停止转换"""
        if self.conversion_worker and self.conversion_worker.isRunning():
            self.conversion_worker.stop()
            self.log("===== 转换已停止 =====")
            self.statusBar.showMessage("转换已停止")
            self.reset_ui_after_conversion()
    
    def update_file_status(self, file_path, status):
        """更新文件状态"""
        for row in range(self.file_table.rowCount()):
            if self.file_table.item(row, 1).text() == file_path:
                status_item = QTableWidgetItem(status)
                status_item.setTextAlignment(Qt.AlignCenter)
                
                # 根据状态设置颜色
                if status == "转换成功":
                    status_item.setForeground(QColor(76, 175, 80))  # 绿色
                elif status == "转换失败" or status == "错误":
                    status_item.setForeground(QColor(244, 67, 54))  # 红色
                
                self.file_table.setItem(row, 2, status_item)
                break
    
    def conversion_completed(self):
        """转换完成"""
        self.log("===== 转换完成 =====")
        self.statusBar.showMessage("转换完成")
        QMessageBox.information(self, "完成", "所有文件转换完成！")
        self.reset_ui_after_conversion()
    
    def reset_ui_after_conversion(self):
        """重置UI状态"""
        self.conversion_worker = None
        self.convert_action.setEnabled(True)
        self.stop_action.setEnabled(False)
        self.progress_bar.setFormat("准备就绪")

if __name__ == "__main__":
    app = QApplication(sys.argv)
    # 设置应用程序样式
    app.setStyle("Fusion")
    
    # 创建并显示主窗口
    window = NB2MDConverter()
    window.show()
    
    # 运行应用程序
    sys.exit(app.exec_())